package com.jingdianjichi.practice.server.service.Impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jingdianjichi.practice.api.common.PageInfo;
import com.jingdianjichi.practice.api.common.PageResult;
import com.jingdianjichi.practice.api.enums.CompleteStatusEnum;
import com.jingdianjichi.practice.api.enums.IsDeletedFlagEnum;
import com.jingdianjichi.practice.api.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.practice.api.req.GetPracticeSubjectsReq;
import com.jingdianjichi.practice.api.req.GetUnCompletePracticeReq;
import com.jingdianjichi.practice.api.vo.*;
import com.jingdianjichi.practice.server.entity.dto.CategoryDTO;
import com.jingdianjichi.practice.server.entity.dto.PracticeSetDTO;
import com.jingdianjichi.practice.server.entity.dto.PracticeSubjectDTO;
import com.jingdianjichi.practice.server.entity.po.*;
import com.jingdianjichi.practice.server.mapper.*;
import com.jingdianjichi.practice.server.service.PracticeService;
import com.jingdianjichi.practice.server.utils.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.DateUtils;
import org.mapstruct.ap.shaded.freemarker.template.utility.DateUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * ClassName:PracticeServiceImpl
 * Package:com.jingdianjichi.practice.server.service.Impl
 * Description:
 *
 * @Author fst
 * @Create 2025/1/17 17:24
 * @Version 1.0
 */

@Service
@Slf4j
public class PracticeServiceImpl implements PracticeService
{

    @Resource
    private SubjectCategoryDao subjectCategoryDao;

    @Resource
    private SubjectMappingDao subjectMappingDao;

    @Resource
    private SubjectLabelDao subjectLabelDao;

    @Resource
    private SubjectDao subjectDao;

    @Resource
    private PracticeSetDao practiceSetDao;

    @Resource
    private PracticeSetDetailDao practiceSetDetailDao;

    @Resource
    private SubjectRadioDao subjectRadioDao;

    @Resource
    private SubjectMultipleDao subjectMultipleDao;

    @Resource
    private PracticeDetailDao practiceDetailDao;

    @Resource
    private PracticeDao practiceDao;


    public List<SpecialPracticeVO> getSpecialPracticeContent()
    {
        List<SpecialPracticeVO> specialPracticeVOList =new LinkedList<>();

        List<Integer> subjectTypeList =new LinkedList<>();

        subjectTypeList.add(SubjectInfoTypeEnum.RADIO.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.JUDGE.getCode());
        subjectTypeList.add(SubjectInfoTypeEnum.MULTIPLE.getCode());
        CategoryDTO categoryDTO =new CategoryDTO();
        categoryDTO.setSubjectTypeList(subjectTypeList);

       List<PrimaryCategoryPO>  poList= subjectCategoryDao.getPrimaryCategory(categoryDTO);

       if(CollectionUtils.isEmpty(poList))
       {
           return specialPracticeVOList;
       }


       poList.forEach(primaryCategoryPO -> {
           SpecialPracticeVO specialPracticeVO=new SpecialPracticeVO();

           specialPracticeVO.setPrimaryCategoryId(primaryCategoryPO.getParentId());

          CategoryPO categoryPO= subjectCategoryDao.selectById(primaryCategoryPO.getParentId());

          specialPracticeVO.setPrimaryCategoryName(categoryPO.getCategoryName());

          CategoryDTO categoryDTOTemp=new CategoryDTO();

          //查询小类
          categoryDTOTemp.setCategoryType(2);

          categoryDTOTemp.setParentId(primaryCategoryPO.getParentId());

         List<CategoryPO> smallPoList = subjectCategoryDao.selectList(categoryDTOTemp);

         if(CollectionUtils.isEmpty(smallPoList))
         {
             return;
         }

         List<SpecialPracticeCategoryVO> categoryList=new LinkedList<>();

         smallPoList.forEach(smallPo->{
             List<SpecialPracticeLabelVO> labelVOList = getLabelVOList(smallPo.getId(),subjectTypeList);
             if(CollectionUtils.isEmpty(labelVOList))
             {
                 return;
             }

             SpecialPracticeCategoryVO specialPracaticeCategoryVO=new SpecialPracticeCategoryVO();
             specialPracaticeCategoryVO.setCategoryId(smallPo.getId());
             specialPracaticeCategoryVO.setCategoryName(smallPo.getCategoryName());

             List<SpecialPracticeLabelVO> specialPracticeLabelVOList=new LinkedList<>();

             labelVOList.forEach(labelVo ->{
                 SpecialPracticeLabelVO specialPracticeLabelVO=new SpecialPracticeLabelVO();
                 specialPracticeLabelVO.setId(labelVo.getId());
                 specialPracticeLabelVO.setAssembleId(labelVo.getAssembleId());
                 specialPracticeLabelVO.setLabelName(labelVo.getLabelName());

                 specialPracticeLabelVOList.add(specialPracticeLabelVO);
             });

             specialPracaticeCategoryVO.setLabelList(specialPracticeLabelVOList);

             categoryList.add(specialPracaticeCategoryVO);
         });
         specialPracticeVO.setCategoryList(categoryList);
         specialPracticeVOList.add(specialPracticeVO);
       });
       return specialPracticeVOList;
    }

    private List<SpecialPracticeLabelVO> getLabelVOList(Long categoryId, List<Integer> subjectTypeList) {
        List<LabelCountPO> countPOList = subjectMappingDao.getLabelSubjectCount(categoryId, subjectTypeList);

        if (CollectionUtils.isEmpty(countPOList)) {
            return Collections.emptyList();
        }

        List<SpecialPracticeLabelVO> labelVOList = new LinkedList<>();

        countPOList.forEach(labelCountPO ->
        {
            SpecialPracticeLabelVO vo = new SpecialPracticeLabelVO();
            vo.setId(labelCountPO.getLabelId());
            vo.setAssembleId(categoryId + "-" + labelCountPO.getLabelId());

            SubjectLabelPO subjectLabelPO = subjectLabelDao.queryById(labelCountPO.getLabelId());

            vo.setLabelName(subjectLabelPO.getLabelName());

            labelVOList.add(vo);
        });
        return labelVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PracticeSetVO addPractice(PracticeSubjectDTO practiceSubjectDTO)
    {
        PracticeSetVO  practiceSetVO=new PracticeSetVO();

        List<PracticeSubjectDetailVO>  practiceSubjectDetailVOList=getPracticeList(practiceSubjectDTO);

        if(CollectionUtils.isEmpty(practiceSubjectDetailVOList))
        {
            return practiceSetVO;
        }


        PracticeSetPO practiceSetPO=new PracticeSetPO();
        //随机生成的套题
        practiceSetPO.setSetType(1);

        List<String> assembleIds =practiceSubjectDTO.getAssembleIds();

        Set<Long> categoryIdSet=new HashSet<>();

        assembleIds.forEach(assembleId->
        {
            String[] split = assembleId.split("-");
            categoryIdSet.add(Long.valueOf(split[0]));
        });

        StringBuffer setName = new StringBuffer();

        int i=1;

        for(Long categoryId:categoryIdSet)
        {
            if(i>2)
            {
                break;
            }

            CategoryPO categoryPO = subjectCategoryDao.selectById(categoryId);
            setName.append(categoryPO.getCategoryName());
            setName.append("、");
            i++;
        }
        setName.deleteCharAt(setName.length() - 1);
        if(i==2)
        {
            setName.append("专项练习");
        }
        else setName.append("等专项练习");

        //填充套卷信息
        practiceSetPO.setSetName(setName.toString());
        String labelId=assembleIds.get(0).split("-")[1];

        SubjectLabelPO subjectLabelPO = subjectLabelDao.selectById(Long.valueOf(labelId));
        practiceSetPO.setPrimaryCategoryId(Long.valueOf(subjectLabelPO.getCategoryId()));
        practiceSetPO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        practiceSetPO.setCreatedBy(LoginUtil.getLoginId());
        practiceSetPO.setCreatedTime(new Date());

        practiceSetDao.add(practiceSetPO);
        Long practiceSetId = practiceSetPO.getId();


        List<PracticeSubjectDetailPO> practiceSubjectDetailPOList = new LinkedList<>();


        practiceSubjectDetailVOList.forEach(e->
        {
            PracticeSubjectDetailPO practiceSubjectDetailPO = new PracticeSubjectDetailPO();
            practiceSubjectDetailPO.setSubjectId(e.getSubjectId());
            practiceSubjectDetailPO.setSetId(practiceSetId);
            practiceSubjectDetailPO.setSubjectType(e.getSubjectType());
            practiceSubjectDetailPO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
            practiceSubjectDetailPO.setCreatedBy(LoginUtil.getLoginId());
            practiceSubjectDetailPO.setCreatedTime(new Date());
            practiceSubjectDetailPOList.add(practiceSubjectDetailPO);
        });

        practiceSetDetailDao.insertBatch(practiceSubjectDetailPOList);

        practiceSetVO.setSetId(practiceSetId);

        return practiceSetVO;
    }

    @Override
    public PracticeSubjectListVO getSubjects(GetPracticeSubjectsReq req) {
        Long setId = req.getSetId();

        PracticeSubjectListVO vo =new PracticeSubjectListVO();
        List<PracticeSubjectDetailVO> practiceSubjectDetailVOS =new LinkedList<>();

        List<PracticeSetDetailPO> practiceSetDetailPOS =practiceSetDetailDao.selectBySetId(setId);

        if(CollectionUtils.isEmpty(practiceSetDetailPOS))
        {
            return vo;
        }


        String loginId=LoginUtil.getLoginId();

        Long practiceId = req.getPracticeId();

        practiceSetDetailPOS.forEach(e->
        {
            PracticeSubjectDetailVO practiceSubjectDetailVO =new PracticeSubjectDetailVO();
            practiceSubjectDetailVO.setSubjectId(e.getSubjectId());
            practiceSubjectDetailVO.setSubjectType(e.getSubjectType());
            if(Objects.nonNull(practiceId))
            {
                PracticeDetailPO practiceDetailPO=practiceDetailDao.selectDetail(practiceId,e.getSubjectId(),e.getCreatedBy());
                if(Objects.nonNull(practiceDetailPO)&& StringUtils.isNotBlank(practiceDetailPO.getAnswerContent()))
                {
                    practiceSubjectDetailVO.setIsAnswer(1);
                }
                else {
                    practiceSubjectDetailVO.setIsAnswer(0);
                }

            }
            practiceSubjectDetailVOS.add(practiceSubjectDetailVO);
        });


        vo.setSubjectList(practiceSubjectDetailVOS);

         PracticeSetPO practiceSetPO = practiceSetDao.selectById(setId);

         vo.setTitle(practiceSetPO.getSetName());


         if(Objects.isNull(practiceId)) {
             Long newPracticeId = insertUnCompletePractice(setId);
             vo.setPracticeId(newPracticeId);
         }
         else
         {
             updateUncompletePractice(practiceId);
             PracticePO practicePO = practiceDao.selectById(practiceId);
             vo.setTimeUse(practicePO.getTimeUse());
             vo.setPracticeId(practiceId);
         }

         return vo;
    }


    private void updateUncompletePractice(Long practiceId)
    {
        PracticePO practicePO=new PracticePO();
        practicePO.setId(practiceId);
        practicePO.setSubmitTime(new Date());

        practiceDao.update(practicePO);
    }

    private Long insertUnCompletePractice(Long practiceSetId)
    {
        PracticePO practicePO=new PracticePO();
        practicePO.setSetId(practiceSetId);
        practicePO.setCompleteStatus(CompleteStatusEnum.UN_COMPLETE.getCode());
        practicePO.setCreatedBy(LoginUtil.getLoginId());
        practicePO.setTimeUse("00:00:00");
        practicePO.setSubmitTime(new Date());
        practicePO.setCorrectRate(new BigDecimal("0.00"));
        practicePO.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        practicePO.setCreatedTime(new Date());

        practiceDao.insert(practicePO);

        return practicePO.getId();
    }

    @Override
    public PracticeSubjectVO getPracticeSubject(PracticeSubjectDTO dto)
    {

        PracticeSubjectVO practiceSubjectVO=new PracticeSubjectVO();
        SubjectPO subjectPO = subjectDao.selectById(dto.getSubjectId());

        practiceSubjectVO.setSubjectName(subjectPO.getSubjectName());
        practiceSubjectVO.setSubjectType(subjectPO.getSubjectType());

        if(dto.getSubjectType()==SubjectInfoTypeEnum.RADIO.getCode())
        {
            List<PracticeSubjectOptionVO> practiceSubjectOptionVOList = new LinkedList<>();

            List<SubjectRadioPO> radioSubjectPOS =subjectRadioDao.selectBySubjectId(dto.getSubjectId());

            radioSubjectPOS.forEach(e->
            {
                PracticeSubjectOptionVO practiceSubjectOptionVO =new PracticeSubjectOptionVO();
                practiceSubjectOptionVO.setOptionContent(e.getOptionContent());
                practiceSubjectOptionVO.setOptionType(e.getOptionType());

                practiceSubjectOptionVOList.add(practiceSubjectOptionVO);
            });
            practiceSubjectVO.setOptionList(practiceSubjectOptionVOList);
        }
        else if(dto.getSubjectType()==SubjectInfoTypeEnum.MULTIPLE.getCode())
        {
            List<PracticeSubjectOptionVO> practiceSubjectOptionVOList = new LinkedList<>();

            List<SubjectMultiplePO> multipleSubjectPOS =subjectMultipleDao.selectBySubjectId(dto.getSubjectId());

            multipleSubjectPOS.forEach(e->
            {
                PracticeSubjectOptionVO practiceSubjectOptionVO =new PracticeSubjectOptionVO();
                practiceSubjectOptionVO.setOptionContent(e.getOptionContent());
                practiceSubjectOptionVO.setOptionType(e.getOptionType());

                practiceSubjectOptionVOList.add(practiceSubjectOptionVO);
            }
            );
            practiceSubjectVO.setOptionList(practiceSubjectOptionVOList);
        }
        return practiceSubjectVO;
    }

    private List<PracticeSubjectDetailVO> getPracticeList(PracticeSubjectDTO dto)
    {
        List<PracticeSubjectDetailVO> practiceSubjectDetailVOList=new LinkedList<>();

        List<Long> excludeSubjectIds=new LinkedList<>();

        //设置题目数量
        Integer radioSubjectCount=10;
        Integer judgeSubjectCount=4;
        Integer multipleSubjectCount=6;
        Integer totalSubjectCount=20;

        dto.setSubjectCount(radioSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.RADIO.getCode());
        assembleList(dto,practiceSubjectDetailVOList,excludeSubjectIds);

        dto.setSubjectCount(judgeSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.JUDGE.getCode());
        assembleList(dto,practiceSubjectDetailVOList,excludeSubjectIds);

        dto.setSubjectCount(multipleSubjectCount);
        dto.setSubjectType(SubjectInfoTypeEnum.MULTIPLE.getCode());
        assembleList(dto,practiceSubjectDetailVOList,excludeSubjectIds);

        if(practiceSubjectDetailVOList.size()==totalSubjectCount)
        {
            return practiceSubjectDetailVOList;
        }

        //补充题目
        Integer remainCount=totalSubjectCount-practiceSubjectDetailVOList.size();
        dto.setSubjectCount(remainCount);
        dto.setSubjectType(SubjectInfoTypeEnum.RADIO.getCode());
        assembleList(dto,practiceSubjectDetailVOList,excludeSubjectIds);

        return practiceSubjectDetailVOList;

    }

    private List<PracticeSubjectDetailVO> assembleList(PracticeSubjectDTO dto, List<PracticeSubjectDetailVO> practiceSubjectDetailVOList,
                              List<Long> excludeSubjectIds) {
        //加入排除题目id
        dto.setExcludeSubjectIds(excludeSubjectIds);

        List<SubjectPO> subjectPOList = subjectDao.getPracticeSubject(dto);


        if (CollectionUtils.isEmpty(subjectPOList)) {
            return practiceSubjectDetailVOList;
        }

        subjectPOList.forEach(e -> {
            PracticeSubjectDetailVO vo = new PracticeSubjectDetailVO();
            vo.setSubjectId(e.getId());
            vo.setSubjectType(e.getSubjectType());
            excludeSubjectIds.add(e.getId());
            practiceSubjectDetailVOList.add(vo);
        });
        return practiceSubjectDetailVOList;
    }

    public PageResult<PracticeSetVO> getPresetContent(PracticeSetDTO dto)
    {
        PageResult<PracticeSetVO> pageResult=new PageResult<>();
        PageInfo pageInfo = dto.getPageInfo();

        pageResult.setPageNo(pageInfo.getPageNo());

        pageResult.setPageSize(pageInfo.getPageSize());

        int start= (pageInfo.getPageNo()-1)* pageInfo.getPageSize();

        Integer count=practiceSetDao.getListCount(dto);

        if(count==0)
        {
            return pageResult;
        }

        List<PracticeSetPO> setPOList=practiceSetDao.getSetList(dto,start,pageInfo.getPageSize());

        List<PracticeSetVO> list =new LinkedList<>();

        setPOList.forEach(e->{
            PracticeSetVO vo =new PracticeSetVO();
            vo.setSetId(e.getId());
            vo.setSetName(e.getSetName());
            vo.setSetHeat(e.getSetHeat());
            vo.setSetDesc(e.getSetDesc());

            list.add(vo);
        });

        pageResult.setRecords(list);
        pageResult.setTotal(count);

        return pageResult;
    }

    @Override
    public PageResult<UnCompletePracticeSetVO> getUnCompletePractice(GetUnCompletePracticeReq req)
    {
        PageResult<UnCompletePracticeSetVO> pageResult=new PageResult<>();
        PageInfo pageInfo = req.getPageInfo();

        pageResult.setPageNo(pageInfo.getPageNo());
        pageResult.setPageSize(pageInfo.getPageSize());

        int start= (pageInfo.getPageNo()-1)* pageInfo.getPageSize();

        String loginId=LoginUtil.getLoginId();

        Integer count=practiceDao.getUnCompletePracticeCount(loginId);

        if(count==0)
        {
            return pageResult;
        }
        List<PracticePO> practicePOList=practiceDao.getUnCompletePractice(loginId,start,pageInfo.getPageSize());

        if(log.isInfoEnabled())
        {
            log.info("PracticeServiceImpl.getUnCompletePractice{}", JSON.toJSONString(practicePOList));
        }

        List<UnCompletePracticeSetVO> list =new LinkedList<>();
        practicePOList.forEach(e->{
            UnCompletePracticeSetVO vo =new UnCompletePracticeSetVO();
            vo.setSetId(e.getSetId());
            vo.setPracticeId(e.getId());
            vo.setPracticeTime(DateUtils.formatDate(e.getSubmitTime(),"yyyy-MM-dd"));
            PracticeSetPO practiceSetPO=practiceSetDao.selectById(e.getSetId());
            vo.setTitle(practiceSetPO.getSetName());
            list.add(vo);
        });
        pageResult.setRecords(list);
        pageResult.setTotal(count);
        return pageResult;
    }

}
